<?php
/**
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author     Martin Neitz
 */

// must be run within Dokuwiki
if (!defined('DOKU_INC')) die();

if (!defined('DOKU_LF')) define('DOKU_LF', "\n");
if (!defined('DOKU_TAB')) define('DOKU_TAB', "\t");

class helper_plugin_object extends DokuWiki_Syntax_Plugin {
 
  var $objspc = '';
  var $spcPath = '';
  
  function getInfo(){
    return array(
      'author' => 'Martin Neitz',
      'email'  => 'martin.dokuwiki@gmail.com',
      'date'   => '2007-01-19',
      'name'   => 'Contact Plugin (helper class)',
      'desc'   => 'this helper for the Object plugin.',
      'url'    => '',
    );
  }
  
  function getMethods(){
    $result = array();
    $result[] = array(
      'name'   => 'renderEntryForm',
      'desc'   => 'renders the entry form for a given object specification',
      'params' => array('mode' => 'string','renderer' => 'string','ns' => 'string','objspc' => 'string','specificationPaht' => 'string'),
      'return' => array('return' => 'boolean'),
    );

    return $result;
  }


  function renderEntryForm($mode, &$renderer, $ns, $objspc, $spcPath, $object = array()){
    global $ID;
    
  include($spcPath . '\\' . $objspc . '\\objspc.php');
        
  $this->objspc = $objspc;
  $this->spcPath = $spcPath;

  foreach($os as $fieldname => $definition){
     list ($type, $size, $prefix, $suffix) = $definition;
      
      // set retrieve the value of the field
      
     $fieldvalue = $object[$fieldname];
      
     switch ($type){
       case 'descriptivtext':
           $class='descriptivtext';
           $renderer->doc .= DOKU_TAB . DOKU_TAB . DOKU_TAB . '<tr><th colspan=2 class="'. $class .'">'. $this->getLang($fieldname . '_edt') . '</th></tr>' . DOKU_LF;
           break;
        case 'text':
           $class='text';
           $renderer->doc .= 
           DOKU_TAB . DOKU_TAB . DOKU_TAB . '<tr>'. DOKU_LF .
           DOKU_TAB . DOKU_TAB . DOKU_TAB . '<th class="'. $class .'"><label for="obj_' . $fieldname . '">' . $this->getLang($fieldname) . ':</label></th>'. DOKU_LF .
           DOKU_TAB . DOKU_TAB . DOKU_TAB . '<td class="'. $class .'"><INPUT type="text" id="obj_'. $fieldname . '" size=' . $size . ' name=obj_'. $fieldname .' value="'. $fieldvalue .'" ></td>'. DOKU_LF .
           DOKU_TAB . DOKU_TAB . DOKU_TAB . '</tr>' . DOKU_LF;
           break;
       case 'multitext':
           $class='multitext';
           $renderer->doc .= 
           DOKU_TAB . DOKU_TAB . DOKU_TAB . '<tr>'. DOKU_LF . 
           DOKU_TAB . DOKU_TAB . DOKU_TAB . '<th class="'. $class .'"><label for="obj_' . $fieldname . '">' . $this->getLang($fieldname) . ':</label></th>' . DOKU_LF.
           DOKU_TAB . DOKU_TAB . DOKU_TAB . '<td class="'. $class .'"><TEXTAREA id="obj_'. $fieldname . '" name=obj_' .$fieldname . ' rows=7 cols='. $size .'>'. $fieldvalue .'</TEXTAREA></td>' . DOKU_LF.
           DOKU_TAB . DOKU_TAB . DOKU_TAB . '</tr>' . DOKU_LF;
           break;
       case 'onoff':
           $class='onoff';
           $checked ='';
           if ($fielvalue) $checked = "checked='checked'";
           $renderer->doc .= 
           DOKU_TAB . DOKU_TAB . DOKU_TAB . '<tr>' . DOKU_LF.
           DOKU_TAB . DOKU_TAB . DOKU_TAB . '<th class="'. $class .'"><label for="obj_' . $fieldname . '">' . $this->getLang($fieldname) . '</label></th>' . DOKU_LF.
           DOKU_TAB . DOKU_TAB . DOKU_TAB . '<td class="'. $class .'"><input type="checkbox" id="obj_'. $fieldname . '" name=obj_'. $fieldname . ' value=\''. $fieldname .'\''.$checked.'></td>' . DOKU_LF.
           DOKU_TAB . DOKU_TAB . DOKU_TAB . '</tr>' . DOKU_LF;
           break;
       case 'singlechoice':
           $class='singlechoice';
           $renderer->doc .= 
           DOKU_TAB . DOKU_TAB . DOKU_TAB . '<tr>'. DOKU_LF.
           DOKU_TAB . DOKU_TAB . DOKU_TAB . '<th class="'. $class . '"><label for="obj_' . $fieldname . '">' . $this->getLang($fieldname) . ':</label></th>'. DOKU_LF.
           DOKU_TAB . DOKU_TAB . DOKU_TAB . '<td class="'. $class . '"><select id="obj_'. $fieldname .'" name=obj_'. $fieldname .' >'. DOKU_LF; 
      
           foreach($definition['_choices'] as $option){
               $selected = '';
               if ($fieldvalue == $option) $selected = " selected ";
               $renderer->doc .= 
               DOKU_TAB . DOKU_TAB . DOKU_TAB . DOKU_TAB . '<option '. $selected .' value=\'' . $option . '\' >'. $this->getLang($option) . '</option>' . DOKU_LF;
           };
         
           $renderer->doc .=  
           DOKU_TAB . DOKU_TAB . DOKU_TAB . '</select></td></tr>'. DOKU_LF;  
           break;
       case 'seperator':
           $renderer->doc .= DOKU_TAB . DOKU_TAB . DOKU_TAB . '<tr><th colspan=2><hr /></th></tr>' . DOKU_LF;
           break;
            }
  } 
  return true;
  }    


  function renderObject($mode, &$renderer, $obj, $objspc, $spcPath){
  
  include($spcPath . '\\' . $objspc . '\\objspc.php');
      
  $this->objspc = $objspc;
  $this->spcPath = $spcPath;


  foreach($os as $fieldname => $definition){
     list ($type, $size, $prefix, $suffix) = $definition;
    
    $fieldvalue = $obj[$fieldname];
            
    if($fieldvalue or $type == 'seperator' or $type == 'descriptivtext'){
        
        // get the correct value to be displayed
        if ($type == 'singlechoice'){
            $fieldvalue = $this->getLang($fieldvalue);
        }      
    
        //  render the value with the pre and suffix if needed
        if ($prefix or $suffix) {
            $fieldvalue = $this->_render_text($prefix . $fieldvalue . $suffix);
        }
            
      switch ($type){
        case 'descriptivtext':
        
            $class='descriptivtext';
            $renderer->doc .= DOKU_TAB . DOKU_TAB . DOKU_TAB . '<tr><th colspan=2 class="'. $class .'">'. $this->getLang($fieldname . '_dsp') . '</th></tr>' . DOKU_LF;
            break;
         case 'text':
            $class='text';
            $renderer->doc .= 
            DOKU_TAB . DOKU_TAB . DOKU_TAB . '<tr>'. DOKU_LF .
            DOKU_TAB . DOKU_TAB . DOKU_TAB . '<th class="'. $class .'"><label for="' . $fieldname . '">' . $this->getLang($fieldname) . ':</label></th>'. DOKU_LF .
            DOKU_TAB . DOKU_TAB . DOKU_TAB . '<td class="'. $class .'">' .$fieldvalue .'</td>'. DOKU_LF .
            DOKU_TAB . DOKU_TAB . DOKU_TAB . '</tr>' . DOKU_LF;
            break;
        case 'multitext':
            $class='multitext';
            $renderer->doc .= 
            DOKU_TAB . DOKU_TAB . DOKU_TAB . '<tr>'. DOKU_LF . 
            DOKU_TAB . DOKU_TAB . DOKU_TAB . '<th class="'. $class .'"><label for="' . $fieldname . '">' . $this->getLang($fieldname) . ':</label></th>' . DOKU_LF.
            DOKU_TAB . DOKU_TAB . DOKU_TAB . '<td class="'. $class .'">'. $fieldvalue. '</td>' . DOKU_LF.
            DOKU_TAB . DOKU_TAB . DOKU_TAB . '</tr>' . DOKU_LF;
            break;
        case 'onoff':
            $class='onoff';
            $checked = "";
            If ($obj[$fieldname] = $fieldname) $checked = "checked"; 
            $renderer->doc .= 
            DOKU_TAB . DOKU_TAB . DOKU_TAB . '<tr>' . DOKU_LF.
            DOKU_TAB . DOKU_TAB . DOKU_TAB . '<th class="'. $class .'"><label for="' . $fieldname . '">' . $this->getLang($fieldname) . '</label></th>' . DOKU_LF.
            DOKU_TAB . DOKU_TAB . DOKU_TAB . '<td class="'. $class .'"><input type="checkbox" id="'. $fieldname . '" name=\''. $fieldname .'\' value=\''. $fieldname . '\' DISABLED '. $checked .'></td>' . DOKU_LF.
            DOKU_TAB . DOKU_TAB . DOKU_TAB . '</tr>' . DOKU_LF;
            break;
        case 'singlechoice':
            $class='singlechoice';
            $renderer->doc .= 
            DOKU_TAB . DOKU_TAB . DOKU_TAB . '<tr>'. DOKU_LF.
            DOKU_TAB . DOKU_TAB . DOKU_TAB . '<th class="'. $class . '"><label for="' . $fieldname . '">' . $this->getLang($fieldname) . ':</label></th>'. DOKU_LF.
            DOKU_TAB . DOKU_TAB . DOKU_TAB . '<td class="'. $class . '">' . $fieldvalue . DOKU_LF . '</td></tr>'. DOKU_LF;
            break; 
        case 'seperator':
            $renderer->doc .= DOKU_TAB . DOKU_TAB . DOKU_TAB . '<tr><th colspan=2><hr /></th></tr>' . DOKU_LF;
            break;
      }
  
    }
  }    
  return true;
  }



   /* This function builds an array of the defined object based on the specification  
    *  $obj[fieldname] = 'value'
    */

  function pars_object($objstr, $objspc, $spcPath){
     
    include($spcPath . '\\' . $objspc . '\\objspc.php');  


    /**  $sortfile[ValueStartPosition] = Array (Fieldname , ValueStartPosition)
     *   ----------------------------------------------------------------------
     *   This Array will hold all the found Fieldnames and their startposition in
     *   the MatchString. 
     *   The key of the Array is the startposition and by sorting this array i 
     *   get the sequence of how the positions need to be processed                 
     */
    
    $sortfile = array();
    
    foreach($os as $fieldname => $element){
               
        $pos = strpos($objstr, '-' . $fieldname . '=');
        if ($pos) {
          $sortfile[$pos] = array ($fieldname, $pos);
        }  
    }
    ksort ($sortfile, SORT_NUMERIC);
    
    /** -----------This could be eliminated if sort would work correctly---------
     *   as sort does not give result the correct sequence this loop builds an new array
     *   $[ValueStartPosition] = Array (Fieldname , ValueStartPosition)
     */      
    
    $helper = array();

    $index = 0;    
    
    foreach($sortfile as $key => $value){

      $helper[$index] = $value;               
      $index++;
    }
    $sortfile = $helper;
    
    // -------------------------------------------------------------------------
    
       
    /**
     *  This loop will create the needed couples Fieldname and Value out of the 
     *  Matchstring.     
     */       
       
    $obj = array();
    $index = 0;
    
    while ($index < count($sortfile)) {

        if($sortfile[$index +1]){
          $obj[$sortfile[$index][0]] = trim(substr($objstr, ($sortfile[$index][1] + strlen($sortfile[$index][0] ) + 2),
                             ($sortfile[$index +1][1]) - ($sortfile[$index][1] + strlen($sortfile[$index][0] ) + 2) ));
        }else{
          $obj[$sortfile[$index][0]] = trim(substr($objstr, ($sortfile[$index][1] + strlen($sortfile[$index][0] ) + 2)));
        } 
       
        $index++;
    }
    
    return $obj;
  }
  
  /**
   * This function is used to prerender text which is decoraded in the 
   * object specification.
   * e.g.:
   *  ** text **
   *  [[ text ]]         
   *     
   * for more information see the description for the object specification    
   */     
  function _render_text($text){
  
      $modes = p_get_parsermodes();
    
      // Create the parser
      $Parser = & new Doku_Parser();
    
      // Add the Handler
      $Parser->Handler = & new Doku_Handler();
    
      //add modes to parser
      foreach($modes as $mode){
        $Parser->addMode($mode['mode'],$mode['obj']);
      }
    
      // Do the parsing
      trigger_event('PARSER_WIKITEXT_PREPROCESS', $text);
      $instructions  = $Parser->parse($text);
    
      // Create a renderer
      require_once DOKU_INC . 'inc/parser/xhtml.php';
      $Renderer = & new Doku_Renderer_XHTML();
    
      # Load data like smileys into the Renderer here
     
      // Loop through the instructions
      foreach ( $instructions as $instruction ) {
          
          // Execute the callback against the Renderer
          call_user_func_array(array(&$Renderer, $instruction[0]),$instruction[1]);
      }
      // remove the <p> information from the string.
      return substr($Renderer->doc, 5,-5);

  }
  
  
   
  /**
   * Reads the .object metafile
   */
  function readObject($id){
    $file = metaFN($id, '.object');
    $data = unserialize(io_readFile($file, false));
    
    if (!is_array($data) || empty($data)) return false;
    
    $data['file']   = $file;
    $data['exists'] = true;

    return $data;
  }   
  
  /**
   * write the .object metafile
   */  
  
  function writeObject($id, $data){
    if (!is_array($data)) return false;
    $file = ($data['file'] ? $data['file'] : metaFN($id, '.object'));
    
    // remove file and exists keys
    unset($data['file']);
    unset($data['exists']);
    
    // set creation or modification time
    if (!is_array($data['date'])) $data['date'] = array('date' => $data['date']);
    if (!@file_exists($file) || !$data['date']['created']){
      $data['date']['created'] = time();
    } else {
      $data['date']['modified'] = time();
    }

    // save object metadata
    $ok = io_saveFile($file, serialize($data));

    return $ok;
  }  
  
  
   /**
   * Returns an array of Object pages, used for the pagelist plugin
   */
  function getObjects($ns, $num = NULL, $objspc, $spcPath){
    global $conf;
    
    $this->objspc = $objspc;
    $this->spcPath = $spcPath;
               
    require_once(DOKU_INC.'inc/search.php');
        
    include($spcPath . '\\' . $objspc . '\\objspc.php');
        
    $dir = $conf['datadir'].($ns ? '/'.str_replace(':', '/', $ns): '');
        
    // returns the list of pages in the given namespace and it's subspaces
    $items = array();
    search($items, $dir, 'search_allpages', '');
            
    // add pages with comments to result
    $result = array();
    foreach ($items as $item){
      $id   = ($ns ? $ns.':' : '').$item['id'];
      
      // skip if no permission
      $perm = auth_quickaclcheck($id);
      if ($perm < AUTH_READ) continue;
      
      // skip pages without object
      if (!$object = $this->readObject($id)) continue;
      
      // skip pages without the correct object specification
      if ($object['objspc'] != $objspc) continue;
      
      // get metadata
      $meta = array();
      $meta = p_get_metadata($id);
 
      
      /** transform the fieldnames to avoid duplicates foreced by standart names
       *  e.g. title -> first header of a page
       *       title -> title of an contact
       *       
       *  will be transfromed into
       *                                    
       *   "obj_" . fieldname
       */ 
                   
      $transform = array();
            
            
      foreach ($object['object'] as $key => $value){
        $newValue = $value;

        // get the correct value to be displayed
        if ($os[$key][0] == 'singlechoice') $newValue = $this->getLang($value);

        $transform ['obj_' . $key] = $newValue;
      }

      $transform['id']      = $id;
      $transform['user']    = $meta['creator'];
      $transform['file']    = $file;
      $transform['perm']    = $perm;
      $transform['exists']  = true;

      $result[$object['key']] = $transform;

    }
    
    // finally sort user defined key information
    krsort($result);

    
    if (is_numeric($num)) $result = array_slice($result, 0, $num);
      
    return $result;
  }

  /**
   * Returns empty information -> requered from the Pagelist plugin
   */
  function td($id){
    
    return " ";
  }  
   
   
 /**
  *  this function overides the getLang($id) function to handle the specification dependent language files
  */
  
  function setupLocale() {
    if ($this->localised) return;
       
    global $conf;            // definitely don't invoke "global $lang"
    
    $path = $this->spcPath . '/' . $this->objspc .'/lang/';
    
    // don't include once, in case several plugin components require the same language file
    @include($path.'en/lang.php');    
    if ($conf['lang'] != 'en') @include($path.$conf['lang'].'/lang.php');
    
    $this->lang = $lang;
    $this->localised = true;
    }   
   
}
  
//Setup VIM: ex: et ts=4 enc=utf-8 :

  

